import os
import time
import logging
import hashlib
import cgi
import urllib

from time import gmtime, strftime
from google.appengine.ext import webapp
from google.appengine.ext.webapp.util import run_wsgi_app
from google.appengine.ext.webapp import template
from google.appengine.ext import db

from oauthlib import oauth
from myspace.myspaceapi import MySpace
from models import Activity, Subscription
from usersession import User
from admin import AdminPageHandler

import ckeynsecret
import feedparser
import simplejson
import gmemsess
        
class MainPageHandler(webapp.RequestHandler):
    user_id = "demouser"
        
    def get(self):
        self.show_main_page()

    def show_main_page(self):
        self.check_subscription()                

        session=gmemsess.Session(self)
        User.set_current_user(self, self.user_id, self.user_id)
        
        path = os.path.join(os.path.dirname(__file__), 'templates/map.html')
        return self.response.out.write(template.render(path, {}))
    
    """ Checks to see if a subscription has been setup or not
        Makes a subscription request if one's not already present in the datastore
    """
    def check_subscription(self):
        subscription = Subscription.get_user_subscription(self.user_id)
        if subscription:
            return True
        else:
            callback_url = self.request.host_url + "/subscriber." + self.user_id
            subscription_payload = "<?xml version=\"1.0\" encoding=\"utf-8\"?>"\
                                "<Subscription>"\
                                "<Type>All</Type>" \
                                "<Endpoint><![CDATA[" + callback_url + "]]></Endpoint>"\
                                "<Query></Query>"\
                                "<MetaData>UserInfo,UserSubscribers,ApplicationData</MetaData>"\
                                "<BatchSize>1</BatchSize>"\
                                "<Rate>1</Rate>"\
                                "<Format><![CDATA[application/atom+xml]]></Format>"\
                                "</Subscription>"
            return self.perform_subscription(subscription_payload)
    
    def perform_subscription(self, query_xml):
        ms = MySpace(ckeynsecret.CONSUMER_KEY, ckeynsecret.CONSUMER_SECRET)
        status,subscription_id = ms.register_subscription(query_xml)
        if status == 201:
           subscription = Subscription(user=self.user_id, ms_subscription_id=subscription_id)
           subscription.put()
        
"""Called by Ajax client to get updates
"""
class GetUpdatesHandler(webapp.RequestHandler):        
    def get(self):
        current_user = str ( User.get_current_user_id(self) )
        query = Activity.gql("WHERE owner = :owner", owner=current_user)

        activity = query.get()
        if activity:
            encoder = simplejson.JSONEncoder()
            json_activity = {
                        'time': str(activity.updated),
                        'title': activity.title,
                        'content': activity.content,
                        'source': activity.link,
                        'type': activity.object_type,
                        'geopoint':activity.geopoint
                        }
            activity.delete()
            self.response.out.write( encoder.encode(json_activity) )
        else:
            # Nothing in the Queue
            self.response.out.write("Q_EMPTY")
            return        
    
"""Handles feed update callbacks from MySpace
   1. Finds out the target user for the update
   2. Parses the feed and stores in the datastore
""" 
class PubSubHandler(webapp.RequestHandler): 
    def post(self):
        logging.info('Recieved Content Update From Hub') 
        
        body = self.request.body.decode('utf-8')
        logging.info('Post body is %d characters', len(body))

        # find out which user this update is for
        target_user = self.get_target_user()
        if target_user is None:
            logging.info("Unknown target user. Ignoring update")
            return
        
        # Reject feeds if there's not a record of subscription on our end
        # i.e. we deleted a subscription, but, MySpace is still sending it our way
        user_subscription = Subscription.get_user_subscription(target_user)
        if user_subscription is None:
            logging.info('Unknown subscriber. Rejecting update')
            return
        
        data = feedparser.parse(self.request.body)
        if data.bozo:
          logging.error('Bozo feed data. %s: %r',
                         data.bozo_exception.__class__.__name__,
                         data.bozo_exception)
          if (hasattr(data.bozo_exception, 'getLineNumber') and
              hasattr(data.bozo_exception, 'getMessage')):
            line = data.bozo_exception.getLineNumber()
            logging.error('Line %d: %s', line, data.bozo_exception.getMessage())
            #segment = self.request.body.split('\n')[line-1]
            #logging.info('Body segment with error: %r', segment.decode('utf-8'))
          return self.response.set_status(200) # Setting it to 200 so feed does not get deactivated
    
        logging.info('Found %d entries', len(data.entries))
        for entry in data.entries:
          if hasattr(entry, 'content'):
            # This is Atom.
            entry_id = entry.id
            content = entry.content[0].value
            link = entry.get('link', '')
            title = entry.get('title', '')
            point = entry.get('point', '')
          else:
            content = entry.get('description', '')
            title = entry.get('title', '')
            link = entry.get('link', '')
            entry_id = (entry.get('id', '') or link or title or content)
            point = entry.get('point', '')
                          
          object_type = ''  
          if hasattr(entry, 'object-type'):
            object_type = entry.get('object-type', None) # Should be something like this: http://activitystrea.ms/schema/1.0/photo
            if object_type:
                if object_type[-1] == '/': # Strip trailing slash, if any
                    object_type = object_type[0:-1]
                object_type = object_type[object_type.rindex('/')+1:] # Extract the last word (song, status, photo etc)
          
          # For some reason the parser is unable to extract the title for some entries - especially photos
          # let's hack the title together
          #
          if object_type == 'photo':
            if len(title) == 0:
              author = entry.get('author')
              title = author + ' uploaded a photo to MySpace'
              
          #logging.info('Found entry with title = "%s", id = "%s", '
          #             'link = "%s"',
          #             title, entry_id, link)
          
          activity = Activity(
              owner = target_user,
              title=title,
              object_type=object_type,
              content=content,
              link=link,
              geopoint=point)
          try:
              activity.put()
          except:
              pass
          
        self.response.out.write("Update Processed.");
        self.response.set_status(200)

    """Figure out which user this hub request (verification/feed update) is for
       We tacked on the username to the callback url when we sent the subscription over to the
       hub. The request path should have that info in the form of "subscriber.<username>"
    """
    def get_target_user(self):
        req_path = self.request.path
        # look for a '.' in the path. If not, we don't know the user id
        # for whom this update is for
        if req_path.find('.') == -1:
            return None
        target_user = req_path.split('.')[1]
        return target_user
        
application = webapp.WSGIApplication(
                    [
                         ('/', MainPageHandler),
 
                         # Hub callback related
                         ('/subscriber.*', PubSubHandler), # Using ".*" so we can handle multiple subscriptions
                         
                         # Client AJAX related
                         ('/getupdates', GetUpdatesHandler), 
                         
                         # Admin screen 
                         ('/admin', AdminPageHandler),

                    ], 
                    debug=True)

def main():
    run_wsgi_app(application)

if __name__ == "__main__":
    main()
